Howto KVM

KVM est une technologie de virtualisation intégrée au noyau Linux. On l’utilise avec libvirt, une surcouche qui facilite l’utilisation de la virtualisation.

Howto KVM

Installation

Utilisation basique de libvirt

Configuration

Configuration CPU

Configuration mémoire

Configuration réseau

Configuration stockage

Gestion hyperviseur

Création d’une VM

virt-install

virt-manager

virsh define

Stockage

Volumes DRBD/LVM

Format QCOW2

Monter une image QCOW2 via qemu-nbd

Format RAW

Agrandir une image

Réseau

Adresse MAC

Mode bridge

Mode bridge + VLAN

Mode bridge avec openvswitch

Mode réseau NAT (avec libvirt)

Mode réseau NAT (sans libvirt)

QoS / Limitation de bande passante

Snapshots

Options -loadvm / -snapshot (non gérées avec libvirt)

Images dérivées d’une image QCOW2

Mode monitor

Infos sur une VM

Actions sur une VM

Actions sur les snapshots

virsh

Cloner une VM

Migrer une VM

internal error: Attempt to migrate guest to the same host

Renommer une VM

Systemd

Modifier les ressources d’une VM

Nombre de vCPU

RAM

Ajout un disque

Monitoring

Munin

FAQ

Erreur avec certaines commandes virsh

En Debian 8, je ne trouve pas kvm-img

Soucis réseau avec machine clonée

Installation d’une VM sans libvirt

Accéder à virt-manager sur un hyperviseur

Désactiver l’interface réseau d’une VM à chaud

Tips performance

Étendre une image RAW

Étendre un volume disque à chaud

Erreur “Unable to create cgroup”

Souci d’allocation CPU

Problème lors de l’installation

Le bloc nécessaire pour une iso

Disposition qwerty

Virtualisation imbriquée

Machine reboot lors du boot sur fichier .iso pour installation d’un systeme (Debian ou autre).

 

Installation

Pour installer un hyperviseur (machine capable de faire tourner des machines virtuelles) :

# apt install qemu-kvm bridge-utils qemu-utils libvirt-daemon-system libvirt-clients virtinst netcat-openbsd

$ kvm --version

QEMU emulator version 2.8.1(Debian 1:2.8+dfsg-6+deb9u4)

Copyright (c) 2003-2016 Fabrice Bellard and the QEMU Project developers

 

$ virsh -V

Virsh command line tool of libvirt 3.0.0

See web site at http://libvirt.org/

 

Compiled with support for:

 Hypervisors: QEMU/KVM LXC UML Xen LibXL OpenVZ VMware VirtualBox Test

 Networking: Remote Network Bridging Interface netcf Nwfilter VirtualPort

 Storage: Dir Disk Filesystem SCSI Multipath iSCSI LVM RBD Sheepdog ZFS

 Miscellaneous: Daemon Nodedev AppArmor SELinux Secrets Debug DTrace Readline Modular

Installation de virt-manager :

# apt install virt-manager spice-client-gtk gir1.2-spice-client-gtk-3.0

Utilisation basique de libvirt

Un démon libvirtd tourne sur l’hyperviseur, il peut être redémarré sans impact sur les VMs :

# systemctl restart libvirtd

La commande virsh permet de réaliser des opérations en ligne de commande :

# virsh list --all

# virsh start <vm-name>

# virsh shutdown <vm-name>

# virsh destroy <vm-name>

# virsh edit <vm-name>

Pour un accès « graphique », installer sur le poste client :

# apt install virt-manager netcat-openbsd

Note : Il est déconseillé de se connecter directement en root.

Les VMs définies pour tourner sur l’hyperviseur ont un fichier de définition XML dans le répertoire /etc/libvirt/qemu/.

Configuration

Un hyperviseur KVM doit avoir des CPUs supportant la virtualisation, une bonne quantité de RAM, une configuration réseau spécifique et l’accès à du stockage adapté à votre utilisation (si besoin, un SAN ou un setup DRBD/LVM).

Configuration CPU

Un hyperviseur KVM doit avoir des CPUs supportant la virtualisation.

Cela s’active en général via le BIOS de la machine. Si ce n’est pas activé, vous aurez une erreur KVM: disabled by BIOS

Configuration mémoire

On conseille d’avoir une certaine marge de RAM par rapport à la somme de la mémoire allouée à chaque VM, surtout si vous activez du cache au niveau des disques des VMs (ce qui est conseillé pour de bonnes performances).

On conseille également de configurer au moins 10 Go de swap sur l’hyperviseur afin d’éviter que le mécanisme Out-Of-Memory Killer ne se déclenche au moindre pic de mémoire.

Enfin, on conseille d’ajuster le paramètre oom_score_adj entre les machines critiques et non critiques :

@hourly test -s /var/run/libvirt/qemu/VM-non-critique.pid && echo '800' > /proc/$(cat /var/run/libvirt/qemu/VM-non-critique.pid)/oom_score_adj

@hourly test -s /var/run/libvirt/qemu/VM-critique.pid && echo '-800' > /proc/$(cat /var/run/libvirt/qemu/VM-critique.pid)/oom_score_adj

Configuration réseau

On conseille l’utilisation du mode bridge pour le réseau.
On crée un bridge br0 liée à l’interface eth0 :

# brctl addbr br0

Puis on ajuste le fichier /etc/network/interfaces ainsi :

#source-directory /etc/network/interfaces.d

auto eth0

iface eth0 inet manual

 

auto br0

iface br0 inet static

   address <address>

   netmask <netmask>

   gateway <gateway>

   bridge_ports eth0

   up echo 0 > /sys/class/net/br0/bridge/multicast_snooping

Note 1 : il est nécessaire de désactiver le multicast_snooping pour assurer un bon fonctionnement d’IPv6

Note 2 : il est nécessaire de commenter source-directory /etc/network/interfaces.d car cela fait boguer libvirt

/!\ : s’assurer d’avoir bien installé bridge-utils et configuré le firewall avant de redémarrer

On conseille aussi de ne pas faire transiter les paquets par iptables, cela a notamment l’avantage de ne pas créer d’états quand les paquets transitent vers les machines virtuelles :

sysctl -w net.bridge.bridge-nf-call-iptables=0

echo "net.bridge.bridge-nf-call-iptables=0" >> /etc/sysctl.d/zzz-evolinux_custom.conf

On conseille aussi d’optimiser la partie réseau du noyau : https://wiki.evolix.org/HowtoDebian/Reseau#haute-performance

Configuration stockage

https://libvirt.org/storage.html

Nous utilisons principalement :

Gestion hyperviseur

En cas de souci, il est important de connaître l’état de l’hyperviseur. On met donc en place des crons du type :

@hourly rsync -a --delete /etc/libvirt/qemu/*xml kvm2.example.com:/root/libvirt-kvm/

@daily virsh list |ssh kvm2.example.com "cat >/root/libvirt-kvm/virsh-list.txt"

Création d’une VM

virt-install

Avoir un ISO disponible sur l’hyperviseur (pour Debian, télécharger l’ISO netinst sur http://cdimage.debian.org/debian-cd/current/amd64/iso-cd/) puis l’on crée une VM ainsi :

# virt-install --connect=qemu:///system \

  --name=template \

  --cpu mode=host-passthrough --vcpus=1 \

  --ram=512 \

  --disk path=/path/template.qcow2,bus=virtio,cache=none,size=42,format=qcow2 \

  --network=bridge:br0,model=virtio \

  --noautoconsole --graphics vnc,listen=127.0.0.1,keymap=fr \

  --cdrom=/home/images/debian-8.6.0-amd64-netinst.iso

Notes :

Lien vers le ticket de ce bug

--cpu mode=SandyBridge --vcpus=1 \

Ce qui donne pour l’installation complète sur kvmdev par exemple :

# virt-install --connect=qemu:///system \

  --name=template \

  --cpu mode=SandyBridge --vcpus=1 \

  --ram=512 \

  --disk path=/path/template.qcow2,bus=virtio,cache=none,size=42,format=qcow2 \

  --network=bridge:br0,model=virtio \

  --noautoconsole --graphics vnc,listen=127.0.0.1,keymap=fr \

  --cdrom=/home/images/debian-8.6.0-amd64-netinst.iso

On peut ensuite se connecter en VNC via l’hyperviseur et réaliser l’installation :

$ vncviewer -via kvm.example.com 127.0.0.1:<port VNC>

Note : on peut connaître le port VNC d’une VM avec la commande virsh qemu-monitor-command <vm-name> --hmp "info vnc"

virt-manager

Nous déconseillons l’installation via virt-manager !!
Certes, l’installation est plus conviviale (car graphique) mais :

Si vous utilisez tout de même virt-manager, il faudra donc revenir sur les options une fois la VM créée :

virsh define

http://libvirt.org/formatdomain.html

Vous pouvez écrire votre propre fichier de définition XML puis l’injecter :

# virsh define template.xml

# virsh start template

Stockage

Les stockages disponibles doivent être visibles par libvirt :

# virsh pool-list --all

# virsh vol-list <pool-name>

 

# virsh vol-delete --pool <pool-name> <vol-name>

 

# virsh help pool

 Storage Pool (help keyword 'pool'):

    find-storage-pool-sources-as   find potential storage pool sources

    find-storage-pool-sources      discover potential storage pool sources

    pool-autostart                 autostart a pool

    pool-build                     build a pool

    pool-create-as                 create a pool from a set of args

    pool-create                    create a pool from an XML file

    pool-define-as                 define a pool from a set of args

    pool-define                    define (but don't start) a pool from an XML file

    pool-delete                    delete a pool

    pool-destroy                   destroy (stop) a pool

    pool-dumpxml                   pool information in XML

    pool-edit                      edit XML configuration for a storage pool

    pool-info                      storage pool information

    pool-list                      list pools

    pool-name                      convert a pool UUID to pool name

    pool-refresh                   refresh a pool

    pool-start                     start a (previously defined) inactive pool

    pool-undefine                  undefine an inactive pool

    pool-uuid                      convert a pool name to pool UUID

 

# virsh help volume

 Storage Volume (help keyword 'volume'):

    vol-clone                      clone a volume.

    vol-create-as                  create a volume from a set of args

    vol-create                     create a vol from an XML file

    vol-create-from                create a vol, using another volume as input

    vol-delete                     delete a vol

    vol-download                   download volume contents to a file

    vol-dumpxml                    vol information in XML

    vol-info                       storage vol information

    vol-key                        returns the volume key for a given volume name or path

    vol-list                       list vols

    vol-name                       returns the volume name for a given volume key or path

    vol-path                       returns the volume path for a given volume name or key

    vol-pool                       returns the storage pool for a given volume key or path

    vol-resize                     resize a vol

    vol-upload                     upload file contents to a volume

    vol-wipe                       wipe a vol

Volumes DRBD/LVM

voir HowtoLVM et HowtoDRBD

Format QCOW2

Ce format est spécifique à QEMU. C’est un format à taille variable (indépendamment du système de fichiers), et il dispose de fonctionnalités avancées permettant notamment de gérer des snapshots à chaud.

Création d’une image QCOW2 :

# qemu-img create -f qcow2 test0.qcow2 5G

Informations sur une image QCOW2 :

# qemu-img info debian1.qcow2

image: debian1.qcow2

file format: qcow2

virtual size: 12G (12884901888 bytes)

disk size: 908M

cluster_size: 65536

Agrandir une image :

De façon similaire au format RAW, on peut agrandir une image QCOW2. Voir http://blog.majerti.fr/resize-qcow2.html

Convertir une image RAW en QCOW2 :

# qemu-img convert -f qcow2 -O raw test0.qcow2 test0.img

Il est aussi possible de convertir un volume LVM par exemple vers du qcow2. Note : Dans la définition d’une VM il ne faut pas oublié de changer le type pour spécifier que c’est un fichier de type qcow2

# qemu-img convert -O qcow2 /dev/LV_GROUP/LV_NAME /home/images/ma-super-vm.qcow

Monter une image QCOW2 via qemu-nbd

qemu-nbd permet de créer un point de montage NBD (Network Block Device) :

# modprobe nbd max_part=16;

# qemu-nbd -c /dev/nbd0 test0.qcow2;

# partprobe /dev/nbd0;

/dev/nbd0 est ensuite utilisable pour fdisk :

# fdisk /dev/nbd0

Command (m for help): p

Vous pouvez ensuite (un)mounter vos partitions situées dans votre image QCOW2. Note : si vous avez du LVM, vous devez activer les VG via vgscan && vgchange -ay

Cela peut ensuite être stoppé via :

# qemu-nbd -d /dev/nbd0

Format RAW

L’avantage de ce format est sa simplicité ! C’est tout simplement une suite d’octets.. Cela permet de monter les partitions facilement (merci kpartx). Sous Linux, grâce au principe du sparse file (fichier à trou), c’est également un format à taille variable.

Création de l’image :

# qemu-img create -f raw test0.img 5G

Mountage de l’image (attention à ne jamais la monter en cours de fonctionnement) :

# modprobe dm-mod  # Si kpartx renvoi un /proc/misc: No entry for device-mapper found

# kpartx -v -a test0.img

loop1p1 : 0 9912042 /dev/loop1 63

loop1p2 : 0 562275 /dev/loop1 9912105

loop1p5 : 0 562212 loop1p1 63

 

# fdisk -l /dev/loop1

# mount /dev/mapper/loop1p1 /mnt/test0

# umount /mnt/test0

# kpartx -d test0.img

Convertir ume image RAW en QCOW2 :

# qemu-img convert -f raw -O qcow2 test0.img test0.qcow2

Editer un fichier à l’intérieur d’une image (une fois la VM éteinte) :

# virt-edit -d domain /path/to/file

Agrandir une image

# qemu-img resize host.img +50G

Image resized.

ou on peut utiliser dd, exemple pour une taille finale de 80G :

# dd if=/dev/zero of=host.img seek=80G count=0 bs=1

0+0 records in

0+0 records out

0 bytes (0 B) copied, 1.302e-05 s, 0.0 kB/s

# kpartx -v -a host.img

add map loop0p1 (254:4): 0 314572737 linear /dev/loop0 63

# fdisk -l /dev/loop0

 

Disk /dev/loop0: 161.1 GB, 161061273600 bytes

[…]

# sfdisk -d /dev/loop0 >~/loop0.parts

# parted /dev/loop0

[…]

Voir http://trac.evolix.net/infogerance/wiki/HowtoParted

# kpartx -d host.img

loop deleted : /dev/loop0

 

# kpartx -v -a host.img

add map loop0p1 (254:4): 0 314572737 linear /dev/loop0 63

# e2fsck -f /dev/mapper/loop0p1

e2fsck 1.42.5 (29-Jul-2012)

Pass 1: Checking inodes, blocks, and sizes

Pass 2: Checking directory structure

Pass 3: Checking directory connectivity

Pass 4: Checking reference counts

Pass 5: Checking group summary information

/dev/mapper/loop0p1: 46712/6111232 files (8.3% non-contiguous), 20257932/24414775 blocks

 

# resize2fs /dev/mapper/loop0p1

resize2fs 1.42.5 (29-Jul-2012)

Resizing the filesystem on /dev/mapper/loop0p1 to 39321592 (4k) blocks.

The filesystem on /dev/mapper/loop0p1 is now 39321592 blocks long.

# mount /dev/mapper/loop0p1 /mnt

 

# df -h /mnt

/dev/mapper/loop0p1 148G   76G   72G  52% /mnt

 

# umount /mnt

# kpartx -d host.img

loop deleted : /dev/loop0

Réseau

Les interfaces réseau en place doivent être visibles par libvirt :

# virsh iface-list --all

# virsh net-list --all

 

# virsh help interface

 Interface (help keyword 'interface'):

    iface-begin                    create a snapshot of current interfaces settings, which can be later committed (iface-commit) or restored (iface-rollback)

    iface-bridge                   create a bridge device and attach an existing network device to it

    iface-commit                   commit changes made since iface-begin and free restore point

    iface-define                   define (but don't start) a physical host interface from an XML file

    iface-destroy                  destroy a physical host interface (disable it / "if-down")

    iface-dumpxml                  interface information in XML

    iface-edit                     edit XML configuration for a physical host interface

    iface-list                     list physical host interfaces

    iface-mac                      convert an interface name to interface MAC address

    iface-name                     convert an interface MAC address to interface name

    iface-rollback                 rollback to previous saved configuration created via iface-begin

    iface-start                    start a physical host interface (enable it / "if-up")

    iface-unbridge                 undefine a bridge device after detaching its slave device

    iface-undefine                 undefine a physical host interface (remove it from configuration)

 

# virsh help network

 Networking (help keyword 'network'):

    net-autostart                  autostart a network

    net-create                     create a network from an XML file

    net-define                     define (but don't start) a network from an XML file

    net-destroy                    destroy (stop) a network

    net-dhcp-leases                print lease info for a given network

    net-dumpxml                    network information in XML

    net-edit                       edit XML configuration for a network

    net-event                      Network Events

    net-info                       network information

    net-list                       list networks

    net-name                       convert a network UUID to network name

    net-start                      start a (previously defined) inactive network

    net-undefine                   undefine a persistent network

    net-update                     update parts of an existing network's configuration

    net-uuid                       convert a network name to network UUID

Adresse MAC

On peut générer l’adresse MAC d’une VM KVM avec la commande suivante :

$ echo $(echo -n 52:54:00 ; for i in `seq 1 3`; do echo -n `echo ":$RANDOM$RANDOM" | cut -n -c -3`; done)

Mode bridge

Attention : Cette procédure est seulement pour Stretch.

On va créer le bridge à chaud et basculer l’interface principale dedans (eth0, eno1, …). Pour éviter de perdre bêtement la main, on va sauvegarder la configuration actuelle.

# apt install bridge-utils

# cp /etc/network/interfaces /var/backups/

# vim /etc/network/interfaces

 

auto eth0

iface eth0 inet manual

 

auto br0

iface br0 inet static

  bridge_ports eth0

  up echo 0 > /sys/class/net/br0/bridge/multicast_snooping

  address <address>/<netmask>

  gateway <gateway>

 

# screen -S network -dm bash -c "sleep 300; cp /var/backups/interfaces /etc/network/; systemctl stop networking; systemctl start networking"

# screen -S reboot -dm bash -c "sleep 600; reboot"

# systemctl restart networking; ip a d <address>/<netmask> dev eth0; ip a a <address>/<netmask> dev br0; ip r d default via <gateway> dev eth0; ip r a default via <gateway> dev br0

Si tout se passe bien, tuez les screen. Sinon attendez 5 min, si vous récupérez la main, tuer le screen de reboot. Sinon attendre 10 min que le serveur redémarre avec l’ancienne configuration réseau.

Mode bridge + VLAN

Vous pouvez faire passer plusieurs VLANs dans votre bridge, afin de permettre l’accès depuis vos VMs à différents VLANs.

Sur l’hyperviseur on aura ainsi une configuration réseau du type (paquet vlan à installer) :

auto br0

iface eth0 inet manual

iface br0 inet manual

    bridge_ports eth0

    up echo 0 > /sys/class/net/br0/bridge/multicast_snooping

auto br0.42

iface br0.42 inet static

   address <address>

   netmask <netmask>

   gateway <gateway>

Dans les VMs, on aura ainsi une configuration réseau « VLANisée », voir http://trac.evolix.net/infogerance/wiki/HowtoDebian/Reseau#VLAN

Mode bridge avec openvswitch

Notamment utile pour utiliser avec le réseau RPN Online de l’hébergeur français ONLINE/Dedibox.

/etc/network/interfaces :

# LAN bridge over RPN

# https://documentation.online.net/fr/dedicated-server/tutorials/network/rpn-proxmox-openvswitch

auto br1

iface br1 inet manual

    ovs_type OVSBridge

    post-up ovs-vsctl add-port br1 gre0 -- set interface gre0 type=gre options:remote_ip='10.XX.XX.XX'

    post-up ip link set ovs-system up

    post-up ip link set br1 up

Créer un fichier XML définissant le réseau :

<network>

  <name>br1</name>

  <forward mode='bridge'/>

  <bridge name='br1'/>

  <virtualport type='openvswitch'/>

</network>

# virsh net-define br1.xml

# virsh net-start br1

# virsh net-autostart br1

Mode réseau NAT (avec libvirt)

Le mode NAT peut être intéressant si l’on ne peut pas avoir d’IP dans le réseau de l’hyperviseur.

Avec libvirt, il suffit d’installer :

# apt install dnsmasq ebtables

Et l’on peut configurer avec un réseau NAT avec virt-manager ou virsh net-create et un fichier XML du type :

<network connections='1'>

  <name>nat0</name>

  <uuid>f94578a3-3b7f-4c60-a441-d1f86920fb59</uuid>

  <forward dev='eth0' mode='nat'>

    <nat>

      <port start='1024' end='65535'/>

    </nat>

    <interface dev='eth0'/>

  </forward>

  <bridge name='virbr0' stp='on' delay='0'/>

  <mac address='52:54:00:de:ad:41'/>

  <domain name='nat0'/>

  <ip address='192.0.2.1' netmask='255.255.255.0'>

    <dhcp>

      <range start='192.0.2.128' end='192.0.2.254'/>

    </dhcp>

  </ip>

</network>

Mode réseau NAT (sans libvirt)

Note : une raison d’utiliser le NAT est qu’une interface Wi-Fi n’est pas toujours utilisable dans un bridge :

# brctl addif br0 wlan0

can't add wlan0 to bridge br0: Operation not supported

On va donc prendre l’exemple où vous avez une interface Wi-Fi wlan0 :

# echo 1 > /proc/sys/net/ipv4/ip_forward

# iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE

Vous pouvez ainsi lancer votre KVM ainsi (on lance un CD-ROM d’OpenBSD dans notre cas) :

# kvm -hda routeur0.qcow2 -cdrom cd48.iso -boot d -m 384 -k fr -net nic,macaddr=52:54:00:de:ad:42,model=e1000 -net tap,vlan=0,ifname=tap0

Une fois démarré, attribuez l’IP 192.0.2.1/24 à l’interface tap0 sur votre portable. Dans vos machines virtuelles, prenez une adresse IP dans la plage 192.0.2.0/24 et indiquez 192.0.2.1 comme route par défaut.

Normalement, c’est tout !

Si vous lancez plusieurs machines virtuelles, vous penserez à modifier l’adresse MAC et à utiliser des tapN différents. Si vous voulez les faire communiquer entre elles, vous devrez simplement créer un bridge entre les interfaces tap :

# brctl addbr br0

# brctl addif br0 tap0

# brctl addif br0 tap1

# brctl addif br0 tap2

etc.

QoS / Limitation de bande passante

Libvirt permet aussi de faire de la QoS sur l’interface réseau. On va utiliser un bloc bandwidth qui va permettre de contrôler le débit.

    <interface type='bridge'>

      <mac address='00:00:00:00:00:00'/>

      <source bridge='br0'/>

      <bandwidth>

        <inbound average='1000' peak='5000' burst='1024'/>

        <outbound average='128' peak='256' burst='256'/>

      </bandwidth>

      <model type='virtio'/>

      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>

    </interface>

On peut jouer sur plusieurs paramètres :

La documentation complète se trouve sur https://libvirt.org/formatdomain.html#elementQoS

Snapshots

L’utilisation du format de stockage QCOW2 permet d’avoir des snapshots à chaud !
On peut créer plusieurs snapshots de l’état disque/mémoire, et restaurer en quelques secondes.

Avec libvirt, création/restauration/suppression de snapshots se gèrent de façon conviviale avec virt-manager ou on peut aussi utiliser virsh :

# virsh snapshot-create-as template-evolinux snapshot1

 

# virsh snapshot-list template

 Name                 Creation Time             State

------------------------------------------------------------

 snapshot1            2016-12-27 01:46:58 +0000 running

 

# virsh snapshot-info --snapshotname snapshot1 template

Name:           snapshot1

Domain:         template

Current:        yes

State:          running

Location:       internal

Parent:         -

Children:       0

Descendants:    0

Metadata:       yes

 

# virsh help snapshot

 Snapshot (help keyword 'snapshot'):

    snapshot-create                Create a snapshot from XML

    snapshot-create-as             Create a snapshot from a set of args

    snapshot-current               Get or set the current snapshot

    snapshot-delete                Delete a domain snapshot

    snapshot-dumpxml               Dump XML for a domain snapshot

    snapshot-edit                  edit XML for a snapshot

    snapshot-info                  snapshot information

    snapshot-list                  List snapshots for a domain

    snapshot-parent                Get the name of the parent of a snapshot

    snapshot-revert                Revert a domain to a snapshot

On peut aussi gérer les snapshots via le Mode Monitor et les commandes savevm, loadvm, info snapshots.

Note : les snapshots créés avec savevm ne seront pas visible via libvirt.

Options -loadvm / -snapshot (non gérées avec libvirt)

On peut démarrer directement sur un snapshot s0 avec l’option -loadvm :

$ kvm -hda debian1.qcow2 -m 512 -net nic,macaddr=<mac_address> -net tap,script=/etc/qemu-ifup \

    -curses -monitor tcp:127.0.0.1:<port monitor>,server,nowait -loadvm s0

On peut démarrer une VM avec le mode -snapshot où rien n’est réellement écrit sur le disque :

$ kvm -hda debian1.qcow2 -m 512 -net nic,macaddr=<mac_address> -net tap,script=/etc/qemu-ifup \

    -curses -monitor tcp:127.0.0.1:<port monitor>,server,nowait -snapshot

Au prochain redémarrage, le système revient à son état précédent. Si nécessaire on peut tout de même forcer l’écriture en passant l’option commit all en mode monitor :

(qemu) commit all

Images dérivées d’une image QCOW2

http://wiki.qemu.org/Documentation/CreateSnapshot

Une option intéressante avec le format QCOW2 est la possibilité de créer une image d’une installation de base et de créer des dérivées à partir de cette image. Non seulement cela permet de repartir d’une installation déjà faite, mais cela permet aussi une optimisation de la place (l’image dérivée est en Copy-on-Write de celle de base) voire même de la mémoire selon les rumeurs :-)

Création d’une image dérivée :

# qemu-img create -f qcow2 -b install-debian-base.qcow2base serveur01.qcow2snap

Formatting 'serveur01.qcow2snap', fmt=qcow2 size=12884901888 backing_file='install-debian-base.qcow2base' encryption=off cluster_size=0

 

# qemu-img info serveur01.qcow2snap

image: serveur01.qcow2snap

file format: qcow2

virtual size: 12G (12884901888 bytes)

disk size: 140K

cluster_size: 65536

backing file: install-debian-base.qcow2base (actual path: install-debian-base..qcow2base)

/!\ Attention, ne jamais modifier une image de base si elle a des images dérivées sous peine de tout perdre !

Mode monitor

http://en.wikibooks.org/wiki/QEMU/Monitor
https://doc.opensuse.org/documentation/leap/virtualization/html/book.virt/cha.qemu.monitor.html

Le mode monitor est une option de kvm et permet d’effectuer diverses actions (état de la VM, action sur la VM, snapshots, etc.).

libvirt crée automatiquement un mode monitor qu’il utilise (donc non accessible directement), mais on peut aussi l’utiliser via :

# virsh qemu-monitor-command <vm-name> --hmp "info block"

Si on utilise kvm sans libvirt, on peut créer un mode monitor accessible via telnet :

$ kvm […] -monitor tcp:127.0.0.1:<port monitor>,server,nowait

 

$ telnet 127.0.0.1 <port monitor>

Trying 127.0.0.1…

Connected to 127.0.0.1.

Escape character is '^]'.

QEMU 0.9.1 monitor - type 'help' for more information

(qemu)

 

$ echo system_powerdown | nc 127.0.0.1 <port monitor>

Infos sur une VM

(qemu) info block

(qemu) info blockstats

(qemu) info network

(qemu) info uuid

Actions sur une VM

Extinction ACPI d’une VM :

(qemu) system_powerdown

Pause/Resume d’une VM :

(qemu) stop

(qemu) cont

Envoyer une combinaison clavier :

(qemu) sendkey ctrl-alt-f1

Mot de passe VNC :

(qemu) change vnc password

Ajout de disques/périphériques à chaud :

(qemu) drive_add ?

(qemu) device_add ?

Actions sur les snapshots

Ceci n’est disponible que pour les VMs utilisant un stockage QCOW2.

Créer et lister les snapshots :

(qemu) savevm s0

savevm s0

(qemu) info snapshots

info snapshots

Snapshot devices: ide0-hd0

Snapshot list (from ide0-hd0):

ID        TAG                 VM SIZE                DATE       VM CLOCK

1         s0                      20M 2010-11-14 20:07:09   00:16:01.182

(qemu)

Restauration à chaud :

(qemu) loadvm s0

Pour réaliser des snapshots automatiques sans arrêt de la machine, on pourra avoir un script du type :

#!/bin/sh

echo "savevm snap.current" | telnet 127.0.0.1 <port>

sync

cp debian1.qcow2 debian.current.qcow2

/!\ Attention, avec libvirt si l’on passe directement par le mode monitor les snapshots ne seront pas visibles par libvirt qui gère un état XML des snapshots. On pourra néanmoins faire :

# virsh qemu-monitor-command <vm-name> --hmp "savevm snap.current"

# virsh qemu-monitor-command <vm-name> --hmp "info snapshots"

virsh

http://libvirt.org/sources/virshcmdref/html-single/

La commande virsh permet de faire de nombreuses manipulations en ligne de commande :

## Lister les VMs actives

# virsh list

 

## Lister les VMs actives/inactives

# virsh list --all

 

## Démarrer/Stopper proprement une VM

# virsh start <vm-name>

# virsh shutdown <vm-name>

 

## Forcer l'extinction d'une VM (elle n'est pas détruite !)

# virsh destroy <vm-name>

 

## Informations avancées sur une VM

# virsh dominfo <vm-name>

 

## Activer/désactiver le démarrage automatique d'une VM

# virsh autostart <vm-name>

# virsh autostart --disable <vm-name>

 

## Dumper la configuration d'une VM dans un fichier de définition XML

# virsh dumpxml <vm-name> > <vm-name>.xml

 

## Créer/détruire une définition de VM

# virsh define <vm-name>.xml

# virsh undefine <vm-name>

 

## Mettre sur pause/réactiver une VM

# virsh suspend <vm-name>

# virsh resume <vm-name>

 

## Modifier les options d'une VM

# virsh edit <vm-name>

/!\ Attention, il faut toujours utiliser virsh edit et ne jamais éditer le fichier dans /etc/libvirt/qemu/ qui est régulièrement écrasé !

La commande virsh peut également être utilisée à distance :

# VIRSH_DEFAULT_CONNECT_URI='qemu+ssh://root@kvm.example.com/system' virsh list --all

Note : par défaut VIRSH_DEFAULT_CONNECT_URI=‘qemu:///system’

Cloner une VM

Via clic-droit sur virt-manager ou en CLI :

# virt-clone --original <mytemplate-domainame> --name <newmachine> --file <newmachine>.img

Cela permet de dupliquer un domaine existant avec notamment changement de l’adresse MAC de la carte réseau.

Une fois la machine démarrée, il faudra modifier son hostname, son adresse IP et ses clés SSH.

# rm /etc/udev/rules.d/70-persistent-net.rules

# hostname foo ; echo foo > /etc/hostname

# rm /etc/ssh/ssh_host_* ; dpkg-reconfigure openssh-server

# vim /etc/network/interfaces

On peut utiliser l’option --preserve-data pour copier les données vers une image vierge existante (par exemple de taille différente) :

# virt-clone --original <mytemplate-domainame> --name <newmachine> --file <newmachine>.img --preserve-data

Migrer une VM

https://libvirt.org/migration.html

Note : Il faut s’assurer d’ouvrir les ports TCP 49152 à 49215 entre les machines car par défaut libvirtd utilise ces ports pour faire des netcat des données !

Pour une migration à chaud, il faut avoir un CPU identique (à voir selon l’option un storage commun pour les disques (SAN, réplication DRBD, etc.).

Pour envoyer une VM locale test vers l’hyperviseur foo :

# VIRSH_DEFAULT_CONNECT_URI='qemu:///system' virsh migrate --live --unsafe --verbose test qemu+ssh://foo/system

Migration: [100 %]

Pour rappatrier une VM test depuis l’hyperviseur foo :

# VIRSH_DEFAULT_CONNECT_URI='qemu+ssh://foo/system' virsh migrate --live --unsafe --verbose test qemu:///system

Migration: [100 %]

Note : on peut faire cela via virt-manager mais le mode --unsafe (utile si un cache disque est configuré) n’est pas supporté…

Si l’on a plusieurs interfaces réseau sur l’hyperviseur (par exemple un réseau dédié entre les hyperviseurs), il faut l’indiquer à libvirt sinon il tente de passer par l’interface principale :

# virsh migrate --live --unsafe --verbose test qemu+ssh://192.0.2.2/system tcp://192.0.2.2/

Migration: [100 %]

Attention la migration d’une VM ne déplace pas sa définition ! Il est donc impératif de faire un virsh define de son fichier de définition sur l’hyperviseur de destination de la migration sous peine de n’avoir plus aucune trace de la VM une fois éteinte ! On conseille aussi de nettoyer virsh undefine sur l’hyperviseur de départ pour éviter les confusions.

Astuce : si le lien entre les deux hyperviseurs n’est pas rapide et que la mémoire de ma VM est très sollicitée, la migration peut ne jamais se finir et boucler entre 80 et 99%… si c’est le cas, mettez sur “pause” la VM et cela devrait permettre de terminer la migration sans avoir à éteindre la VM (évidemment pendant qu’elle est sur “pause” la VM sera inaccessible).

internal error: Attempt to migrate guest to the same host

Sur des machines très proches matériellement, il est possible d’avoir un souci du fait d’un system-uuid identique sur les deux hyperviseurs :

error: internal error: Attempt to migrate guest to the same host 12341234-1234-1234-1234-1234123412341234

Il faut éditer /etc/libvirt/libvirtd.conf (cf # UUID of the host) et ajouter un autre uuid puis redémarrer le service libvirtd pour prise en compte.

Renommer une VM

Si un mauvais choix a été fait au départ et qu’il faut renommer toute la VM (y compris la partie LVM et DRBD), la procédure est facile et rapide mais elle doit se faire à froid (VM éteinte). La plupart des opération doit se faire sur les 2 nœuds DRBD (ici tic et tac, et la VM est active seulement sur tic).

  1. 1.Une fois la VM éteinte il faut couper la synchro DRBD :  

tic $ drbdadm down <old resource>

tac $ drbdadm down <old resource>

  1. 2.Il faut ensuite faire le renommage de la partie LVM, pour chaque volume de la VM  

tic $ lvrename <VG name> <old LV name> <new LV name>

tac $ lvrename <VG name> <old LV name> <new LV name>

  1. 3.On renomme le fichier de définition de la ressource :  

tic $ mv /etc/drbd.d/<old resource>.res /etc/drbd.d/<new resource>.res

tac $ mv /etc/drbd.d/<old resource>.res /etc/drbd.d/<new resource>.res

  1. 4.On renomme la ressource elle-même sur la première ligne de la définition et on adapte les chemins LVM.  

tic $ vim /etc/drbd.d/<new resource>.res

tac $ vim /etc/drbd.d/<new resource>.res

  1. 5.On peut alors reconnecter les nœuds DRBD :  

tic $ drbdadm up <new resource>

tac $ drbdadm up <new resource>

  1. 6.Sur le nœud DRBD principal, on remet la ressource en primaire :  

tic $ drbdadm primary <new resource>

  1. 7.On renomme la VM elle même :  

tic $ virsh domrename <old DOM name> <new DOM name>

Pour Debian 7 et inférieur, la commande virsh domrename n’existe pas. On peut alors contourner de cette manière :

# cd /etc/libvirt/qemu/

# cp <old DOM name>.xml <new DOM name>.xml

# virsh undefine <old DOM name>

# vim <new DOM name>.xml

# : faire les modifications de l'étape 8 ainsi que le changement de nom dans la balise <name>

# virsh define <new DOM name>.xml

  1. 8.On ajuste les chemins des volumes dans la définition de la VM  

tic $ virsh edit <new DOM name>

  1. 9.On peut enfin démarrer la VM  

tic $ virsh start <new DOM name>

Systemd

libvirt fait appel à systemd (machinectl/systemd-run) pour lancer les processus des VM et les suivre.

Pour avoir le statut :

# machinectl

MACHINE      CONTAINER    SERVICE

qemu-mavm      vm        libvirt-qemu

 

1 machines listed.

# machinectl status qemu-mavm

qemu-mavm(db0b0ff5e71e4ed9813b226f6843729a)

           Since: Mon 2016-02-22 18:17:49 CET; 8 months 25 days ago

          Leader: 33012 (qemu-system-x86)

         Service: libvirt-qemu; class vm

         Address: 192.0.2.1

              OS: Debian GNU/Linux 8 (jessie)

            Unit: machine-qemu\x2dmavm.scope

                  ??33012 qemu-system-x86_64 -enable-kvm -name mavm -S -machine pc-i440fx-2.1,accel=kvm,usb=off -cpu SandyBridge…

En cas de plantage du processus qemu-system, il sera peut être nécessaire de faire un systemctl reset-failed avant de redémarrer la VM :

# systemctl reset-failed machine-qemu\\x2dmavm.scope

Modifier les ressources d’une VM

Nombre de vCPU

Il faut éditer le fichier de définition de la VM et modifier la valeur de la partie <vcpu>:

# virsh edit <vm-name>

Il faut ensuite stopper la VM (bien attendre qu’elle soit réellement stoppée :

# virsh shutdown <vm-name> && watch "virsh list --all"

Ensuite la redémarrer

# virsh start <vm-name>

RAM

L’opération est presque identique à celle pour les vCPU. Il faut changer 2 valeurs dans la définition de la VM : <memory> et <currentMemory>.

Ajout un disque

Créer un fichier XML qui définit le nouveau disque. Exemple :

<disk type='block' device='disk'>

      <driver name='qemu' type='raw' cache='writeback' io='threads'/>

      <source dev='/dev/hdd0/mondisque'/>

      <target dev='vdc' bus='virtio'/>

</disk>

Puis l’ajouter à la machine, et à sa définition.

virsh attach-device <nomMachine> add-disk.xml --live --config

De la même manière, on peut détacher un disque avec virsh detach-device.

Monitoring

Munin

Il existe des plugins Munin pour grapher les ressources CPU/IO/Mémoire de chaque VM :

$ wget https://raw.githubusercontent.com/munin-monitoring/contrib/master/plugins/virtualization/kvm_cpu

$ wget https://raw.githubusercontent.com/munin-monitoring/contrib/master/plugins/virtualization/kvm_io

$ wget https://raw.githubusercontent.com/munin-monitoring/contrib/master/plugins/virtualization/kvm_mem

$ sed -i 's/pidof kvm/pidof qemu-system-x86_64/' kvm_*

Le plugin kvm_io nécessite de tourner en root, /etc/munin/plugin-conf.d/munin-node :

[kvm_io]

user root

FAQ

http://www.linux-kvm.org/page/FAQ

Erreur avec certaines commandes virsh

Solution : tester de positionner la variable VIRSH_DEFAULT_CONNECT_URI

Dans certains cas, elle se positionne par défaut à vbox:///system On peut donc la forcer :

VIRSH_DEFAULT_CONNECT_URI='qemu:///system' virsh list

En Debian 8, je ne trouve pas kvm-img

C’est désormais qemu-img inclu dans le paquet qemu-utils. a priori en Debian 6, c’était qemu-img (inclus par défaut) et en Debian 7 c’était kvm-img (inclus par défaut).

Soucis réseau avec machine clonée

Lorsqu’une machine est clonée avec virt-manager ou virsh, une nouvelle adresse MAC est générée (pour éviter les conflits). Cependant, comme il s’agit d’un clone, l’adresse MAC connue de Udev est toujours présente (dans /etc/udev/rules.d/z25_persistent-net.rules) et l’interface apparait donc comme eth1.

Deux solutions, utiliser eth1 au lieu de eth0, ou corriger /etc/udev/rules.d/z25_persistent-net.rules en mettant à jour l’adresse MAC de eth0 et en supprimant eth1.

Installation d’une VM sans libvirt

# qemu-img create -f qcow2 debian1.qcow2 20G

 

# kvm -hda debian1.qcow2 -cdrom debian-amd64-netinst.iso -boot d -m 512 -net nic,macaddr=<mac_address> -net tap,script=/etc/qemu-ifup -vnc :1 -k fr

<installation via VNC 127.0.0.1:5901 puis boot final>

 

# /usr/bin/screen -S debian1 -d -m kvm -hda debian1.qcow2 -m 512 -net nic,macaddr=<mac_address> -net tap,script=/etc/qemu-ifup \

    -curses -k fr -monitor tcp:127.0.0.1:<port>,server,nowait

Accéder à virt-manager sur un hyperviseur

Installer sur l’hyperviseur et se connecter en ssh -X. Options recommandées :

$ ssh -X -C -c arcfour root@kvm.example.com

Désactiver l’interface réseau d’une VM à chaud

Pour ne pas avoir besoin de redémarrer une VM pour retirer une interface, on peut retirer son interface vnetX sur l’hyperviseur du bridge associé. Le nom de cette interface se trouve avec la commande virsh dumpxml :

# virsh dumpxml <vm-name>

[…]

    <interface type='bridge'>

      <mac address='52:54:00:de:ad:43'/>

      <source bridge='br2'/>

      <target dev='vnet7'/>

      <model type='virtio'/>

      <alias name='net1'/>

      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>

    </interface>

# virsh detach-interface […]

Il suffit ensuite de la retirer du bridge :

# brctl delif br2 vnet7

Tips performance

http://www.linux-kvm.org/page/Tuning_KVM

On peut aussi présenter toutes les instructions du CPU hôte aux machines virtuelles :

  <cpu mode='host-model'>

    <model fallback='allow'/>

  </cpu>

Étendre une image RAW

Pour le sport, voici différentes méthodes pour étendre une image RAW :

# qemu-img resize host.img +50G

# dd if=/dev/zero of=host.img seek=80G count=0 bs=1

# dd oflag=append conv=notrunc if=/dev/zero of=host.img bs=1MB count=20480

Étendre un volume disque à chaud

Note : Ne fonctionne qu’à partir de Jessie

Par exemple avec LVM :

# lvresize -L+100G /dev/vg0/example

# virsh blockresize domain path sizeB

Le blockresize indiquera à la VM de redimenssioner son disque à chaud.

# virsh blockresize myvm /dev/vg0/myvm_rootfs 214748364800B

Erreur “Unable to create cgroup”

Si votre VM a crashé et n’est pas “redémarrable” avec un message “Unable to create cgroup for $VIRTIMAGE: No such file or directory”, notamment il reste des « traces » dans /run/systemd/system/machine-qemu2dfoo.scope vous pouvez faire un reset-failed :

# systemctl status machine-qemu\\x2dfoo.scope

 

# systemctl reset-failed machine-qemu\\x2dfoo.scope

Souci d’allocation CPU

Admettons que vous avez sur l’hyperviseur 32 CPU (cores ou threads, qu’importe), vous affectez 32 vCPU à une VM. Vous constatez que la VM ne peut monter qu’à 1600% d’utilisation, soit 16 vCPU, et vous constatez un steal important (voir top, htop ou Munin). Cela signifie en fait que la VM a démarré avec 32 vCPU, mais ceux-ci sont mappés seulement sur 16 CPU physiques (le premier CPU avec 16 cores par exemple).

C’est un bug lié à libvirt, bug qui est bien connu et corrigé, cependant il impacte toujours le libvirt de Debian Jessie.

Pour corriger le souci à chaud, on peut faire les actions suivantes. Autoriser le CGroup de la machine à utiliser tous les CPU :

# cgset -r cpuset.cpus=0-31 /machine.slice/machine-qemu\\x2d<NOMVM>.scope

Mapper tous les vCPU sur les CPU physiques :

# for i in {0..31}; do virsh vcpupin <NOMVM> $i $i; done

Problème lors de l’installation

Il se peut que apt n’arrive pas à installer complètement kvm. Pour pouvoir finir l’installation :

# systemctl disable libvirtd

# dpkg --configure libvirt-daemon-system

# apt install -f

Cela ne résoud pas forcément le problème.

Le bloc nécessaire pour une iso

Parfois suite à la commande virt-install on n’a toujours pas de CD dans la définition de la VM. Un bloc fonctionnel ressemble à :

    <disk type='file' device='cdrom'>

      <driver name='qemu' type='raw'/>

      <source file='/home/iso/install61.iso'/>

      <target dev='hda' bus='ide'/>

      <readonly/>

      <address type='drive' controller='0' bus='0' target='0' unit='0'/>

    </disk>

Il faudra possiblement rajouter

  <boot dev='cdrom'/>

avant hd dans le block

<os>

  <type arch='x86_64' machine='pc-0.12'>hvm</type>

  <boot dev='hd'/>

</os>

afin de bien booter sur le CD.

Disposition qwerty

Si on veut que le vnc mis en place utilise une disposition de clavier qwerty

<graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' keymap='en-us'>

Virtualisation imbriquée

Dans le cas où l’on veut créer des VMs dans une VM, il peut être nécessaire d’activer la virtualisation imbriquée.

Il faut pour cela éteindre toutes les VMs sur l’hyperviseur, et activer l’option nested avant de redémarrer les VMs :

# modprobe -r kvm_intel

# echo "options kvm-intel nested=1" > /etc/modprobe.d/kvm.conf

# modprobe kvm_intel

Machine reboot lors du boot sur fichier .iso pour installation d’un systeme (Debian ou autre).

Sur certains hyperviseurs et certains CPU, il est possible que le mode CPU host-passthrough provoque un reboot de la VM lorsque l’on boot sur le cd d’install, et que l’on sélectionne le début de l’installation.

Il faut donc, dans le fichier xml, mettre le modèle de CPU de l’hyperviseur correspondant, exemple avec un modèle Sandy Bridge :

 <cpu mode='custom' match='exact'>

    <model fallback='allow'>SandyBridge</model>

  </cpu>